
use std::collections::hash_map::HashMap;

use crate::kvdb::traits::{Table, DBError};


pub struct MockTable {
    name: String,
    data: HashMap<Vec<u8>, Vec<u8>>,
}

impl MockTable {
    pub fn new(name: &str) -> Self {
        MockTable {
            name: name.to_string(),
            data: HashMap::new(),
        }
    }
}

impl Table for MockTable {
    fn name(&self) -> &str {
        &self.name
    }

    // if k exist -> return Error KeyExist
    // if k absent -> return length of inserted bytes
    fn insert(&mut self, k: &[u8], v: &[u8]) -> Result<(), DBError>{
        if self.data.contains_key(k) {
            return Err(DBError::KeyExist)
        }
        self.data.insert(Vec::<u8>::from(k), Vec::<u8>::from(v));
        Ok(())
    }
    // if k exist -> return removed Value
    // if k absent -> return None
    fn remove(&mut self, k: &[u8]) -> Result<Option<Vec<u8>>, DBError> {
        Ok(self.data.remove(k))
    }

    //if k exist ->  update it, return Ok(Some(Value))
    //if k absent ->  return Error(KeyNotExist)
    fn update(&mut self, k: &[u8], v: &[u8]) -> Result<Option<Vec<u8>>, DBError>{
        if !self.data.contains_key(k){
            return Err(DBError::KeyNotExist);
        }
        Ok(self.data.insert(Vec::<u8>::from(k), Vec::<u8>::from(v)))
    }

    //if k exist ->  replace it, return Ok(Some(Value))
    //if k absent ->  insert it, return Ok(None)
    //error -> DBError ???
    fn replace(&mut self, k: &[u8], v: &[u8])-> Result<Option<Vec<u8>>, DBError> {
        Ok(self.data.insert(Vec::<u8>::from(k), Vec::<u8>::from(v)))
    }

    fn exist(&self, k: &[u8]) -> bool{
        self.data.contains_key(k)
    }
    //if exist ->  return Ok(Some(Value))
    //if absent -> return Ok(None)
    //erro -> Error
    fn get(&self, k: &[u8]) -> Result<Option<&Vec<u8>>, DBError> {
        Ok(self.data.get(k))
    }

    fn len(&self) -> usize{
        self.data.len()
    }
}


#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_mock_table(){
        let expect_name = "tab1";
        let mut tab = MockTable::new(expect_name);
        assert_eq!(expect_name, tab.name());
        assert!(tab.insert("key".as_bytes(), "value".as_bytes()).is_ok());

        assert_eq!(1usize, tab.len());
    }
    //TODO:
}

